package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {

	//sleepTest()
	//goroutineTest()

	//num := 1
	//for i := 0; i < 100; i++ {
	//	go Add(&num)
	//}
	//fmt.Println("--" + strconv.Itoa(num))

	onceDoTest()
	time.Sleep(100000)
}

var one sync.Once
var strAv string

func onceDo() {
	one.Do(setA)
	fmt.Println(strAv)
}
func onceDoTest() {
	go onceDo()
	go onceDo()
	go onceDo()
	go onceDo()
}

// setA 只会被调用一次
func setA() {
	strAv = "haha"
	fmt.Println("a")
}

// 如果使用goroutine执行，则返回值会被丢弃【假如有的话】
/*
Go程序从初始化main package并执行main()函数开始，当main()函数返回时，程序退出，
且程序并不等待其他goroutine（非主goroutine）结束。
*/
func Add(x *int) {
	*x += 1
}

/**
goRoutine：让函数立即返回，执行下面的程序 ，创建一个goroutine只需几KB内存
但是因为没有其他程序阻止，这里看不到sleep2second的调用结果，因此在最后让主程序睡眠3s模拟其他业务，这样就相当于goroutine和主程序并发执行，看到其执行结果
*/
func goroutineTest() {
	// 底层也是基于线程实现
	go sleep2second()
	fmt.Println("goroutine下面的程序")
	time.Sleep(time.Second * 3)
	fmt.Println("主程序结束")
}

/**
并发和并行概念这里就不介绍了，主要介绍Go中的并发操作处理
*/
func sleepTest() {
	// 睡眠（阻塞）10s
	now := time.Now()
	fmt.Println("开始睡眠10s\t" + now.String())
	time.Sleep(time.Second * 10)
	fmt.Println("睡眠结束" + time.Now().String())
}

func sleep2second() {
	time.Sleep(time.Second * 2)
	fmt.Println("睡眠2s结束")
}
